﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ExpressionToWhere
{
    internal class ExpressionProcesser
    {
        [ThreadStatic]
        private static Dictionary<string, object> _parameters = null;

        internal static Dictionary<string, object> Parameters
        {
            get
            {
                if (_parameters == null)
                {
                    _parameters = new Dictionary<string, object>();
                }
                return _parameters;
            }
        }

        [ThreadStatic]
        internal static bool Parametric = true;

        private string whereClause = string.Empty;

        internal (string, Dictionary<string, object>) GetResult()
        {
            Dictionary<string, object> CloneParameters(Dictionary<string, object> parameters)
            {
                Dictionary<string, object> clonedParameters = new Dictionary<string, object>();
                foreach (var keyvaluePair in parameters)
                {
                    clonedParameters.Add(keyvaluePair.Key, keyvaluePair.Value);
                }
                return clonedParameters;
            }
            var clonePara = CloneParameters(Parameters);
            Parameters.Clear();
            return (whereClause, clonePara);
        }

        internal void HandleExpression(Expression exp, bool searchNull = true, string dbType = "SqlServer")
        {
            whereClause = GetWhereClause(exp, searchNull, dbType);
        }

        /// <summary>
        /// 处理lambda表达式
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="searchNull">=、大于等于、小于等于、!=是否处理null参数值（true时：Name = null 转换成Name is null，false时：Name = null直接忽略不生成查询条件）</param>
        /// <param name="dbType">数据库类型（SqlServer、MySql、Oracle）</param>
        /// <returns></returns>
        internal static string GetWhereClause(Expression exp, bool searchNull = true, string dbType = "SqlServer")
        {
            BaseExpressionVisitor visitor = null;
            if (exp is BinaryExpression)
            {
                visitor = new BinaryExpressionVisitor(searchNull, dbType);
            }
            else if (exp is MemberExpression)
            {
                visitor = new BooleanMemberExpressionVisitor();
            }
            else if (exp is MethodCallExpression)
            {
                visitor = new MethodCallExpressionVisitor(searchNull, dbType);
            }
            else if (exp is UnaryExpression unaryExpression2 && unaryExpression2.Operand is MethodCallExpression && unaryExpression2.Type == typeof(bool))
            {
                visitor = new UnaryMethodCallExpressionVisitor();
            }
            else if (exp is UnaryExpression unaryExpression1 && unaryExpression1.Operand is MemberExpression && unaryExpression1.Type == typeof(bool))
            {
                visitor = new UnaryBooleanMemberExpressionVisitor();
            }
            else if (exp is UnaryExpression unaryExpression && unaryExpression.Operand is BinaryExpression && unaryExpression.Type == typeof(bool))
            {
                visitor = new UnaryBinaryExpressionVisitor(searchNull, dbType);
            }
            else
            {
                throw new NotSupportedException($"Unknow Expression {exp.GetType()}");
            }

            visitor.Visit(exp);
            return visitor.GetResult().ToString();
        }

        internal static string GetPatameterName(MemberInfo mi, string type = "")
        {
            string key = MemberInfoProcesser.GetParameterName(mi);
            if (!string.IsNullOrEmpty(type)) key = type + key;
            string temp = key;
            int seed = 1;
            while (Parameters.ContainsKey($"@{temp}"))
            {
                temp = key + seed;
                seed++;
            }
            return temp;
        }

        internal static object GetConstant(Expression exp)
        {
            ConstantExpressionVisitor visitor = null;
            if (exp is ConstantExpression)
            {
                visitor = new ConstantExpressionVisitor();
            }
            else if (exp is MemberExpression)
            {
                visitor = new ConstantMemberExpressionVisitor();
            }
            else if (exp is MethodCallExpression)
            {
                visitor = new ConstantMethodCallExpressionVisitor();
            }
            else if (exp is ConditionalExpression)
            {
                visitor = new ConstantConditionalExpressionVisitor();
            }
            else if (exp is ListInitExpression)
            {
                visitor = new ConstantListInitExpressionVisitor();
            }
            else if (exp is NewExpression)
            {
                visitor = new ConstantNewExpressionVisitor();
            }
            else if (exp is MemberInitExpression)
            {
                visitor = new ConstantMemberInitExpressionVisitor();
            }
            else if (exp.GetType().Name == "MethodBinaryExpression")
            {
                visitor = new ConstantMethodBinaryExpressionVisitor();
            }
            else if (exp.GetType().Name == "SimpleBinaryExpression")
            {
                visitor = new ConstantSimpleBinaryExpressionVisitor();
            }
            else if (exp.GetType().Name == "UnaryExpression")
            {
                visitor = new ConstantUnaryExpressionVisitor();
            }
            else
            {
                throw new Exception($"Unknow Expression {exp.GetType()}");
            }
            visitor.Visit(exp);
            return visitor.Value;
        }
    }
}
